﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Algoritmo_di_Dijkstra
{
    class Map
    {
        public SortedList MapWays = new SortedList();
        public SortedList MapBuildings = new SortedList();
        public SortedList MapNodes = new SortedList();
        public SortedList MapConnections = new SortedList();

        public MapRoute route = new MapRoute();
        public MapWay routeStart = new MapWay();
        public MapWay routeArrival = new MapWay();

        public void addNode(MapNode nuovo)
        {
            MapNodes.Add(nuovo.id, nuovo);
        }
        public void addConnection(MapConnection nuovo)
        {
            MapConnections.Add(nuovo, nuovo);
        }
        public void addWay(MapWay nuovo)
        {
            MapWays.Add(nuovo, nuovo);
        }
        public MapWay getWayById(long id)
        {
            return (MapWay)MapWays.GetByIndex(MapWays.IndexOfKey(id));
        }
        public void addBuilding(MapBuilding nuovo)
        {
            MapBuildings.Add(nuovo, nuovo);
        }
        public ArrayList searchRoad(string searchString)
        {
            ArrayList result = new ArrayList();

            foreach (MapWay tmpWay in MapWays.GetValueList())
            {
                if (tmpWay.name.ToLower().Contains(searchString.ToLower()))
                {
                    MapWaySearchResult newResult = new MapWaySearchResult();
                    newResult.id = tmpWay.id;
                    newResult.name = tmpWay.name;
                    newResult.originalMapWay = tmpWay;
                    result.Add(newResult);
                }
            }

            return result;
        }
        public ArrayList searchMapConnectionsOfThisWayByIdWay(long idWay)
        {
            ArrayList result = new ArrayList();

            foreach (MapConnection tmpConnection in MapConnections.GetValueList())
            {
                if (tmpConnection.idWay == idWay)
                {
                    result.Add(tmpConnection);
                }
            }

            return result;
        }

        public void CalcolaRoute()
        {
            foreach (MapConnection tmpMapConnection in searchMapConnectionsOfThisWayByIdWay(23262563))
                route.AddStep(tmpMapConnection);

            foreach (MapConnection tmpMapConnection in searchMapConnectionsOfThisWayByIdWay(24387213))
                route.AddStep(tmpMapConnection);

            foreach (MapConnection tmpMapConnection in searchMapConnectionsOfThisWayByIdWay(23563428))
                route.AddStep(tmpMapConnection);

            foreach (MapConnection tmpMapConnection in searchMapConnectionsOfThisWayByIdWay(4861389))
                route.AddStep(tmpMapConnection);

            foreach (MapConnection tmpMapConnection in searchMapConnectionsOfThisWayByIdWay(23566357))
                route.AddStep(tmpMapConnection);
        }

 //       function A*(start,goal)
 //    closedset := the empty set                 % The set of nodes already evaluated.     
 //    openset := set containing the initial node % The set of tentative nodes to be evaluated.
 //    g_score[start] := 0                        % Distance from start along optimal path.
 //    h_score[start] := heuristic_estimate_of_distance(start, goal)
 //    f_score[start] := h_score[start]           % Estimated total distance from start to goal through y.
 //    while openset is not empty
 //        x := the node in openset having the lowest f_score[] value
 //        if x = goal
 //            return reconstruct_path(came_from,goal)
 //        remove x from openset
 //        add x to closedset
 //        foreach y in neighbor_nodes(x)
 //            if y in closedset
 //                continue
 //            tentative_g_score := g_score[x] + dist_between(x,y)
 
 //            if y not in openset
 //                add y to openset
 
 //                tentative_is_better := true
 //            elseif tentative_g_score < g_score[y]
 //                tentative_is_better := true
 //            else
 //                tentative_is_better := false
 //            if tentative_is_better = true
 //                came_from[y] := x
 //                g_score[y] := tentative_g_score
 //                h_score[y] := heuristic_estimate_of_distance(y, goal)
 //                f_score[y] := g_score[y] + h_score[y]
 //    return failure
 
 //function reconstruct_path(came_from,current_node)
 //    if came_from[current_node] is set
 //        p = reconstruct_path(came_from,came_from[current_node])
 //        return (p + current_node)
 //    else
 //        return the empty path

        //public void A(MapWay start, MapWay goal)
        //{
        //    closedset := the empty set                 % The set of nodes already evaluated.     
        //    openset := set containing the initial node % The set of tentative nodes to be evaluated.
        //    g_score[start] := 0                        % Distance from start along optimal path.
        //    h_score[start] := heuristic_estimate_of_distance(start, goal)
        //    f_score[start] := h_score[start]           % Estimated total distance from start to goal through y.

        //    while openset is not empty
        //        x := the node in openset having the lowest f_score[] value
        //        if x = goal
        //            return reconstruct_path(came_from,goal)
        //        remove x from openset
        //        add x to closedset
        //        foreach y in neighbor_nodes(x)
        //            if y in closedset
        //                continue
        //            tentative_g_score := g_score[x] + dist_between(x,y)

        //            if y not in openset
        //                add y to openset

        //                tentative_is_better := true
        //            elseif tentative_g_score < g_score[y]
        //                tentative_is_better := true
        //            else
        //                tentative_is_better := false
        //            if tentative_is_better = true
        //                came_from[y] := x
        //                g_score[y] := tentative_g_score
        //                h_score[y] := heuristic_estimate_of_distance(y, goal)
        //                f_score[y] := g_score[y] + h_score[y]
        //    return failure
        //}

        //public void reconstruct_path(came_from,current_node)
        //{
        //    if came_from[current_node] is set
        //        p = reconstruct_path(came_from,came_from[current_node])
        //        return (p + current_node)
        //    else
        //        return the empty path
        //}

    }

    class MapNode
    {
        public long id = -1;
        public double x = 0;
        public double y = 0;
    }

    class MapConnection : IComparable
    {        
        public long idWay = -1;
        public long idConnection = -1;
        public MapNode a = new MapNode();
        public MapNode b = new MapNode();
        public double distance = double.PositiveInfinity;

        public int CompareTo(object obj)
        {
            if (obj is MapConnection)
            {
                MapConnection p2 = (MapConnection)obj;

                int compIdWay = idWay.CompareTo(p2.idWay);
                int compIdConnection = idConnection.CompareTo(p2.idConnection);

                if (compIdWay != 0)
                    return compIdWay;
                else
                    return compIdConnection;
            }
            else
                throw new ArgumentException("Object is not a MapConnection.");
        }
    }

    class MapWay : IComparable
    {
        public long id = -1;
        public string name = "n/a";
        public string type = "n/a";
        public bool oneWay = false;

        public int CompareTo(object obj)
        {
            if (obj is MapWay)
            {
                MapWay p2 = (MapWay)obj;
                return id.CompareTo(p2.id);                
            }
            else
                throw new ArgumentException("Object is not a MapWay.");
        }
        public override string ToString()
        {
            return name + "(" + id + ")";
        }
    }

    class MapBuilding : IComparable
    {
        public long id = -1;
        public string name = "n/a";

        public int CompareTo(object obj)
        {
            if (obj is MapBuilding)
            {
                MapBuilding p2 = (MapBuilding)obj;
                return id.CompareTo(p2.id);
            }
            else
                throw new ArgumentException("Object is not a MapBuilding.");
        }
    }

    class MapWaySearchResult
    {
        public long id = -1;
        public string name = "n/a";
        public MapWay originalMapWay = null;
    }

    class MapRoute
    {
        public ArrayList steps = new ArrayList();

        public void AddStep(MapConnection newStep)
        {
            steps.Add(newStep);
        }

        public void ClearSteps()
        {
            steps.Clear();
        }
    }
}
